﻿//-------------------------------------------------------------------------------
// <copyright file="User.cs" company="TaskyMedia LLC">
//     Copyright (c) TaskyMedia LLC.
// </copyright>
//-------------------------------------------------------------------------------

/*
 * Copyright (c) 2010, TaskyMedia LLC
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, 
 * are permitted provided that the following conditions are met:
 *   Redistributions of source code must retain the above copyright notice, this 
 *     list of conditions and the following disclaimer.
 *   Redistributions in binary form must reproduce the above copyright notice, this
 *     list of conditions and the following disclaimer in the documentation and/or
 *     other materials provided with the distribution.
 *   Neither the name of TaskyMedia LLC nor the names of its contributors may be used
 *   to endorse or promote products derived from this software without specific prior
 *   written permission.
 *   
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 * OF SUCH DAMAGE. 
 */

namespace FBGraphApi
{
    using System;
    using System.Collections.Generic;
    using System.Reflection;
    using System.Text;

    /// <summary>
    /// A user profile.
    /// </summary>
    public class User : FBObject
    {
        /// <summary>
        /// Public profile information fields.
        /// </summary>
        private const string PROFILE_PUBLIC_INFO_FIELDS = "id,first_name,last_name,name,gender,link,birthday,bio,quotes";

        /// <summary>
        /// A reference to the <see cref="FBApplication" /> instance that created the object.
        /// </summary>
        private FBApplication _application;

        /// <summary>
        /// Indicates whether the current <see cref="User"/> object is for the current user.
        /// </summary>
        private bool _isSelf;

        /// <summary>
        /// The name of the object inside the Facebook Graph.
        /// </summary>
        private string _objectName;

        /// <summary>
        /// The user's friends.
        /// </summary>
        private FBConnection<FBIdNameObject> _friends;

        /// <summary>
        /// The user's news feed.
        /// </summary>
        private FBConnection<FBStreamObject> _home;

        /// <summary>
        /// Initializes a new instance of the <see cref="User"/> class for the current authorized user.
        /// </summary>
        /// <param name="application">The <see cref="FBApplication" /> instance.</param>
        internal User(FBApplication application)
            : base()
        {
            this._application = application;
            this._isSelf = true;
            this._objectName = "me";

            this.FillProfile();
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="User"/> class for the specified user Id.
        /// </summary>
        /// <param name="application">The <see cref="FBApplication"/> instance.</param>
        /// <param name="userId">The user identifier.</param>
        internal User(FBApplication application, string userId)
            : base()
        {
            this._application = application;
            this._isSelf = false;
            this._objectName = userId;

            this.FillProfile();
        }

        /// <summary>
        /// Gets the user's Id
        /// </summary>
        /// <value>The user's Id.</value>
        [ObjectField("id")]
        public string Id
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets the user's name.
        /// </summary>
        /// <value>The user's name.</value>
        [ObjectField("name")]
        public string Name
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets the user's first name.
        /// </summary>
        /// <value>The user's first name.</value>
        [ObjectField("first_name")]
        public string FirstName
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets the user's last name.
        /// </summary>
        /// <value>The user's last name.</value>
        [ObjectField("last_name")]
        public string LastName
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets a link to the user's profile.
        /// </summary>
        /// <value>The user's profile URL.</value>
        [ObjectField("link")]
        public string Link
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets the user's "About Me" profile section.
        /// </summary>
        /// <value>The user's "About Me" profile section.</value>
        [ObjectField("about")]
        public string AboutMe
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets the user's birthday.
        /// </summary>
        /// <value>The user's birthday.</value>
        [ObjectField("birthday")]
        public string Birthday
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets the user's current location.
        /// </summary>
        /// <value>The user's current location.</value>
        [ObjectField("location")]
        public FBIdNameObject Location
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets the user's hometown.
        /// </summary>
        /// <value>The user's hometown.</value>
        [ObjectField("hometown")]
        public FBIdNameObject Hometown
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets the user's bio.
        /// </summary>
        /// <value>The user's bio.</value>
        [ObjectField("bio")]
        public string Bio
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets the user's favorite quotes.
        /// </summary>
        /// <value>The user's favorite quotes.</value>
        [ObjectField("quotes")]
        public string Quotes
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets the proxied or contact email address granted by the user.
        /// </summary>
        /// <value>The proxied or contact email address granted by the user.</value>
        [ObjectField("email")]
        public string Email
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets the user's website.
        /// </summary>
        /// <value>The user's website.</value>
        [ObjectField("website")]
        public string Website
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets the user's gender.
        /// </summary>
        /// <value>The user's gender.</value>
        [ObjectField("gender")]
        public string Gender
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets the user's religion.
        /// </summary>
        /// <value>The user's religion.</value>
        [ObjectField("religion")]
        public string Religion
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets the user's political view.
        /// </summary>
        /// <value>The user's political view.</value>
        [ObjectField("political")]
        public string PoliticalView
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets the user's Friends.
        /// </summary>
        /// <value>The user's Friends.</value>
        [ObjectConnection("friends")]
        public FBConnection<FBIdNameObject> Friends
        {
            get
            {
                if (this._friends == null)
                {
                    string json = this._application.GetRequest(String.Format("{0}/{1}", this._objectName, "friends"));
                    this._friends = new FBConnection<FBIdNameObject>();
                    this._friends.FillObject(json);
                }

                return this._friends;
            }
        }

        /// <summary>
        /// Gets the user's news feed.
        /// </summary>
        /// <remarks>
        /// Requires the read_stream permission.
        /// </remarks>
        /// <value>The news feed.</value>
        [ObjectConnection("home")]
        public FBConnection<FBStreamObject> NewsFeed
        {
            get
            {
                if (!this._application.DemandPermission(ExtendedPermission.ReadStream))
                {
                    throw new FBPermissionDeniedException("home");
                }

                if (this._home == null)
                {
                    string json = this._application.GetRequest(String.Format("{0}/{1}", this._objectName, "home"));
                    this._home = new FBConnection<FBStreamObject>();
                    this._home.FillObject(json);
                }

                return this._home;
            }
        }

        /// <summary>
        /// Retrieves the profile information for the user from
        /// the Facebook Graph API. The information retrieved is based
        /// on the permissions granted to the application.
        /// </summary>
        private void FillProfile()
        {
            StringBuilder fieldsSb = new StringBuilder();

            // Build a list of extended fields to retrieve based on the permissions
            // of the application.
            ExtendedPermission[] requestedPermissions = this._application.GetExtendedPermissions();
            foreach (ExtendedPermission p in requestedPermissions)
            {
                string[] fieldNames = p.GetProfileFieldNames();
                if (fieldNames != null)
                {
                    foreach (string fieldName in fieldNames)
                    {
                        if (this.ContainsField(fieldName) && p.IsSelf() == this._isSelf)
                        {
                            fieldsSb.AppendFormat("{0},", fieldName);
                        }
                    }
                }
            }

            // Include the basic information
            fieldsSb.Append(PROFILE_PUBLIC_INFO_FIELDS);

            // Retrieve the JSON object
            string jsonData = this._application.GetRequest(this._objectName, new WebRequestParameter("fields", fieldsSb.ToString()));
            this.FillObject(jsonData);
        }
    }
}
